package com.mangofactory.aop.configuration
{
	import com.mangofactory.aop.SimpleCalculator;
	import com.mangofactory.aop.StubAspect;
	import com.mangofactory.aop.aspects.LoggingAspect;
	
	import flash.events.Event;
	
	import mx.core.FlexGlobals;
	
	import org.as3commons.bytecode.reflect.ByteCodeType;
	import org.as3commons.bytecode.reflect.ByteCodeTypeProvider;
	import org.as3commons.reflect.Method;
	import org.as3commons.reflect.Type;
	import org.as3commons.reflect.TypeCache;
	import org.flexunit.asserts.assertEquals;
	import org.flexunit.asserts.assertFalse;
	import org.flexunit.asserts.assertTrue;
	import org.flexunit.async.Async;
	import org.hamcrest.assertThat;
	import org.hamcrest.collection.hasItem;
	import org.hamcrest.object.equalTo;
	import org.hamcrest.object.hasProperty;
	import org.hamcrest.object.hasPropertyWithValue;
	import org.mockito.integrations.havingPropertyOf;

	public class PatternMatchingBuilderTests
	{
		[BeforeClass]
		public static function setupClass():void
		{
//			ByteCodeType.fromLoader(FlexGlobals.topLevelApplication.loaderInfo);
		}
		[Test]
		public function testClassNamePatternMatching():void
		{
			var aspect:StubAspect = new StubAspect();
			var policy:ProxyPolicy = PatternMatchingProxyPolicy.forClasses("com.mangofactory.aop.*").allMethods().buildWithAspect(aspect);
			assertTrue(policy.requiresProxy(SimpleCalculator));
			assertFalse(policy.requiresProxy(TypeCache));
			
			policy = PatternMatchingProxyPolicy.forClasses("com.mangofactory.aop.SimpleCalculator").allMethods().buildWithAspect(aspect);
			assertTrue(policy.requiresProxy(SimpleCalculator));
			assertFalse(policy.requiresProxy(StubAspect));
		}
		[Test]
		public function testMethodNamePatternMatching():void
		{
			var aspect:StubAspect = new StubAspect();
			var policy:ProxyPolicy = PatternMatchingProxyPolicy.forClasses("com.mangofactory.aop.SimpleCalculator").allMethods().buildWithAspect(aspect);
			var methods:Vector.<Method> = policy.getMethodsToProxy(Type.forClass(SimpleCalculator));
			assertEquals(2,methods.length);
			
//			assertThat(methods,hasItem(hasPropertyWithValue("name",equalTo("add"))));
//			assertThat(methods,hasItem(hasPropertyWithValue("name",equalTo("subtract"))));
			
			policy =  PatternMatchingProxyPolicy.forClasses("com.mangofactory.aop.SimpleCalculator").forMethodsMatching("add").buildWithAspect(aspect);
			methods = policy.getMethodsToProxy(Type.forClass(SimpleCalculator));
			assertEquals(1,methods.length);
//			assertThat(methods,hasItem(hasPropertyWithValue("name",equalTo("add"))));
		}
		
		[Test(async)]
		[Ignore]
		public function aspectBuilderWithPatternMatcherAndTypeCacheBuilds():void
		{
			var classProvider:ClassRegistry = new ReflectionClassRegistry();
			
			var aspect:StubAspect = new StubAspect();
			var container:AspectContainer = new AspectContainerBuilder(classProvider)
				.addProxyPolicy(PatternMatchingProxyPolicy.forClasses("com.mangofactory.aop.*").allMethods().buildWithAspect(aspect))
				.addClass(SimpleCalculator)
				.build();
			var handler:Function = Async.asyncHandler(this,onComplete,2000,[container,aspect]);
			container.addEventListener(Event.COMPLETE,handler);
			
		}
		[Ignore]
		[Test(async)]
		public function aspectBuilderWithPatternMatcherBuilds():void
		{
			var aspect:StubAspect = new StubAspect();
			var container:AspectContainer = new AspectContainerBuilder()
				.addProxyPolicy(PatternMatchingProxyPolicy.forClasses("com.mangofactory.aop.*").allMethods().buildWithAspect(aspect))
				.addClass(SimpleCalculator)
				.build();
			var handler:Function = Async.asyncHandler(this,onComplete,2000,[container,aspect]);
			container.addEventListener(Event.COMPLETE,handler);
		}

		private function onComplete(event:Event,params:Array):void
		{
			var container:AspectContainer = params[0] as AspectContainer;
			var aspect:StubAspect = params[1] as StubAspect;
			var calculator:SimpleCalculator = container.newInstance(SimpleCalculator);
			calculator.add(2,3);
			assertTrue(calculator.wasCalled);
			assertTrue(aspect.wasCalled);
		}
		
		
	}
}